home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Muddweller 1.2 / source code / Externals / BigText.cp < prev    next >
Encoding:
Text File  |  1994-02-17  |  27.3 KB  |  1,121 lines  |  [TEXT/MPS ]

  1. /* BigText - Supports large line-wrapped text buffers                         */
  2.  
  3. #include "BigText.h"
  4.  
  5.         // • Implementation use
  6. #ifndef __LOGVIEW__
  7. #include "LogView.h"
  8. #endif
  9.  
  10. #ifndef __NOTRACE__
  11. #include "NoTrace.h"
  12. #endif
  13.  
  14. //------------------------------------------------------------------------------
  15.  
  16. short pCharLocs [kMaxChunk + 1];
  17. RgnHandle BTScroll_clip, BTScroll_scrl, Draw_clip, Draw_tmp;
  18. Boolean pWChars [256] = {
  19.     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,    /* $00 - $0F */
  20.     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  21.     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,    /* $10 - $1F */
  22.     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  23.     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,    /* $20 - $2F */
  24.     FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,  FALSE, FALSE,
  25.     TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,    /* $30 - $3F */
  26.     TRUE,  TRUE,  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  27.     FALSE, TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,    /* $40 - $4F */
  28.     TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
  29.     TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,    /* $50 - $5F */
  30.     TRUE,  TRUE,  TRUE,  FALSE, FALSE, FALSE, FALSE, TRUE,
  31.     FALSE, TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,    /* $60 - $6F */
  32.     TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
  33.     TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,    /* $70 - $7F */
  34.     TRUE,  TRUE,  TRUE,  FALSE, FALSE, FALSE, FALSE, FALSE
  35.     };
  36.  
  37. //------------------------------------------------------------------------------
  38.  
  39. #pragma segment SMUDDocRes
  40.  
  41. pascal void TBigText::BTActivate (Boolean activate, Boolean redraw)
  42. {
  43.     if (fActive != activate) {
  44.         fActive = activate;
  45.         if (redraw) Highlight (fSelStart, fSelEnd);
  46.     }
  47. }
  48.  
  49. //------------------------------------------------------------------------------
  50.  
  51. #pragma segment SMUDDocRes
  52.  
  53. pascal void TBigText::BTAppend (unsigned char *buf, long count,
  54.         Boolean redraw)
  55. {
  56.     VRect area;
  57.     Rect r;
  58.     long drop, oldlen, act;
  59.     
  60.     do {
  61.         if (gMemIsLow)
  62.             drop = count - fMaxLowSize + fLength +
  63.                 ((fBounds.bottom - fBounds.top) * sizeof (short)) / fLineHeight;
  64.         else if (fMaxLength > 0)
  65.             drop = count - fMaxLength + fLength;
  66.         else
  67.             drop = 0;
  68.         if (drop > 0) {
  69.             oldlen = fLength;
  70.             BTDrop (drop, redraw);
  71.             drop -= oldlen - fLength;
  72.             if (drop > 0) {
  73.                 buf += drop;
  74.                 count -= drop;
  75.             }
  76.         }
  77.         BuildReserve (FALSE);
  78.         area = fBounds;
  79.         area.top = area.bottom - fLineHeight;
  80.         act = AppendChars (buf, count);
  81.         if (redraw) {
  82.             area.bottom = fBounds.bottom;
  83.             VRectToRect (&area, &r);
  84.             Draw (&r);
  85.         }
  86.         BuildReserve (TRUE);
  87.         if (!gMemIsLow) {
  88.             fMaxLowSize = fLength + ((fBounds.bottom - fBounds.top) *
  89.                 sizeof (short)) / fLineHeight;
  90.             if (fMemReserve) fMaxLowSize += GetHandleSize (fMemReserve);
  91.         }
  92.         buf += act;
  93.         count -= act;
  94.     } while (count > 0);
  95. }
  96.  
  97. //------------------------------------------------------------------------------
  98.  
  99. #pragma segment SMUDDocRes
  100.  
  101. pascal void TBigText::BTClick (Point *pt, short clicks, Boolean extend)
  102. {
  103.     long anchorstart, anchorend, cloc, runstart, runend;
  104.     Point loc;
  105.     Boolean down;
  106.     
  107.     if (extend) {
  108.         FindRun (clicks, pt->h, pt->v, &runstart, &runend, &cloc);
  109.         if (cloc > (fSelStart + fSelEnd) / 2)
  110.             anchorstart = fSelStart;
  111.         else
  112.             anchorstart = fSelEnd;
  113.         anchorend = anchorstart;
  114.     } else {
  115.         FindRun (clicks, pt->h, pt->v, &anchorstart, &anchorend, &cloc);
  116.         if ((fSelStart != anchorstart) || (fSelEnd != anchorend)) {
  117.             Highlight (fSelStart, fSelEnd);
  118.             Highlight (anchorstart, anchorend);
  119.             fSelStart = anchorstart;
  120.             fSelEnd = anchorend;
  121.         }
  122.     }
  123.     do {
  124.         down = StillDown ();
  125.         GetMouse (&loc);
  126.         ((TLogView *) fSuperView)->ClikLoop (loc);
  127.         FindRun (clicks, loc.h, loc.v, &runstart, &runend, &cloc);
  128.         if (cloc > (anchorstart + anchorend) / 2) {
  129.             Highlight (fSelStart, anchorstart);
  130.             fSelStart = anchorstart;
  131.             Highlight (fSelEnd, runend);
  132.             fSelEnd = runend;
  133.         } else {
  134.             Highlight (fSelEnd, anchorend);
  135.             fSelEnd = anchorend;
  136.             Highlight (fSelStart, runstart);
  137.             fSelStart = runstart;
  138.         }
  139.     } while (down);
  140.     if (fSelStart > fSelEnd) {
  141.         cloc = fSelStart;
  142.         fSelStart = fSelEnd;
  143.         fSelEnd = cloc;
  144.     }
  145. }
  146.  
  147. //------------------------------------------------------------------------------
  148.  
  149. #pragma segment SMUDDocRes
  150.  
  151. pascal void TBigText::BTDrop (long size, Boolean redraw)
  152. {
  153.     long len;
  154.     LSHandle lh;
  155.     
  156.     while (size > 0) {
  157.         len = (**fText).bLength;
  158.         size -= (**fText).bLength;
  159.         if ((**fText).bNext) {
  160.             DropBuf ();
  161.             fSelStart = (fSelStart > len) ? fSelStart - len : 0;
  162.             fSelEnd = (fSelEnd > len) ? fSelEnd - len : 0;
  163.         } else {
  164.             (**fText).bLength = 0;
  165.             (**fText).bLines = 1;
  166.             SetPermHandleSize ((Handle) fText, sizeof (TextBuffer) - kTBSize);
  167.             lh = (**fText).bStarts;
  168.             SetPermHandleSize ((Handle) lh, sizeof (short) * 2);
  169.             (**lh) [1] = 0;
  170.             fLength = 0;
  171.             fBounds.top = fDisplay.bottom;
  172.             fBounds.bottom = fDisplay.bottom + fLineHeight;
  173.             fSelStart = 0;
  174.             fSelEnd = 0;
  175.             size = 0;
  176.         }
  177.     }
  178.     if (fBounds.top > fDisplay.top)
  179.         BTScroll (0, fDisplay.top - fBounds.top, redraw);
  180. }
  181.  
  182. //------------------------------------------------------------------------------
  183.  
  184. #pragma segment SMUDDocRes
  185.  
  186. pascal Handle TBigText::BTGetText (void)
  187. {
  188.     long size, pos, epos;
  189.     Handle h;
  190.     unsigned char *cp;
  191.     TBHandle th, eth;
  192.     
  193.     size = fSelEnd - fSelStart;
  194.     h = NewPermHandle (size);
  195.     if (h) {
  196.         Char2Buf (fSelStart, &th, &pos);
  197.         Char2Buf (fSelEnd, ð, &epos);
  198.         cp = (unsigned char *) *h;
  199.         while (th && (th != eth)) {
  200.             size = (**th).bLength - pos;
  201.             BlockMove ((**th).bBuf + pos, cp, size);
  202.             cp += size;
  203.             th = (**th).bNext;
  204.             pos = 0;
  205.         }
  206.         if (th) BlockMove ((**th).bBuf + pos, cp, epos - pos);
  207.     }
  208.     return h;
  209. }
  210.  
  211. //------------------------------------------------------------------------------
  212.  
  213. #pragma segment SMUDDocRes
  214.  
  215. pascal void TBigText::BTResize (Rect *display, long bleft, long bright,
  216.         Boolean redraw)
  217. {
  218.     long delta, pos, oldv;
  219.     TBHandle th;
  220.     
  221.     if (fAutoWrap && (fBounds.right - fBounds.left != bright - bleft)) {
  222.         fCurVers += 1;
  223.         if (fCurVers == 0) fCurVers = 1;
  224.     }
  225.     fBounds.left = bleft;
  226.     fBounds.right = bright;
  227.     if ((fDisplay.top > fBounds.top) && (fDisplay.bottom >= fBounds.bottom)) {
  228.         Recalc (fBounds.bottom + display->top - display->bottom,
  229.             fBounds.bottom, FALSE);
  230.         delta = display->bottom - fBounds.bottom;
  231.     } else {
  232.         Vert2Buf (fDisplay.top, &th, &pos);
  233.         oldv = Buf2Vert (th, pos);
  234.         delta = display->top - fDisplay.top;
  235.         Recalc (fDisplay.top, display->bottom - delta, FALSE);
  236.         delta += oldv - Buf2Vert (th, pos);
  237.         if (display->bottom > fBounds.bottom + delta)
  238.             delta = display->bottom - fBounds.bottom;
  239.     }
  240.     if (fBounds.top + delta > display->top)
  241.         delta = display->top - fBounds.top;
  242.     fBounds.top += delta;
  243.     fBounds.bottom += delta;
  244.     fDisplay = *display;
  245.     if (redraw) {
  246.         PenNormal ();
  247.         EraseRect (display);
  248.         Draw (display);
  249.     }
  250. }
  251.  
  252. //------------------------------------------------------------------------------
  253.  
  254. #pragma segment SMUDDocRes
  255.  
  256. pascal void TBigText::BTScroll (long h, long v, Boolean redraw)
  257. {
  258.     Rect area;
  259.     long ah, av;
  260.     Boolean toend;
  261.     
  262.     if ((h != 0) || (v != 0)) {
  263.         toend = fBounds.bottom + v <= fDisplay.bottom;
  264.         Recalc (fDisplay.top - v, fDisplay.bottom - v, (v > 0) &&
  265.             (v <= fDisplay.bottom - fDisplay.top));
  266.         if (toend || (fBounds.bottom + v < fDisplay.bottom))
  267.             v = fDisplay.bottom - fBounds.bottom;
  268.         if (fBounds.top + v > fDisplay.top) v = fDisplay.top - fBounds.top;
  269.         fBounds.top += v;
  270.         fBounds.left += h;
  271.         fBounds.bottom += v;
  272.         fBounds.right += h;
  273.         if (redraw) {
  274.             area = fDisplay;
  275.             ah = (h > 0) ? h : -h;
  276.             av = (v > 0) ? v : -v;
  277.             if ((ah < area.right - area.left) &&
  278.                     (av < area.bottom - area.top)) {
  279.                 ScrollRect (&area, (short) h, (short) v, BTScroll_scrl);
  280.                 GetClip (BTScroll_clip);
  281.                 SectRgn (qd.thePort->clipRgn, BTScroll_scrl, BTScroll_scrl);
  282.                 SetClip (BTScroll_scrl);
  283.                 EraseRgn (BTScroll_scrl);
  284.                 area = (**BTScroll_scrl).rgnBBox;
  285.                 Draw (&area);
  286.                 SetClip (BTScroll_clip);
  287.             } else {
  288.                 EraseRect (&area);
  289.                 Draw (&area);
  290.             }
  291.         }
  292.     }
  293. }
  294.  
  295. //------------------------------------------------------------------------------
  296.  
  297. #pragma segment SMUDDocRes
  298.  
  299. pascal void TBigText::BTSetSelect (long selStart, long selEnd,
  300.         Boolean redraw)
  301. {
  302.     if (redraw && fActive) Highlight (fSelStart, fSelEnd);
  303.     fSelStart = selStart;
  304.     fSelEnd = selEnd;
  305.     if (redraw && fActive) Highlight (fSelStart, fSelEnd);
  306. }
  307.  
  308. //------------------------------------------------------------------------------
  309.  
  310. #pragma segment SMUDDocRes
  311.  
  312. pascal void TBigText::BTSetStyle (TextStyle *theStyle, long tabChars,
  313.         Boolean redraw)
  314. {
  315.     GrafPtr savedPort;
  316.     FontInfo info;
  317.     long delta, newheight, newbottom, oldv, pos;
  318.     TBHandle th;
  319.     Rect disp;
  320.     
  321.     GetPort (&savedPort);
  322.     SetPort (gWorkPort);
  323.     SetPortTextStyle (theStyle);
  324.     if ((theStyle->tsFont != fStyle.tsFont) ||
  325.             (theStyle->tsSize != fStyle.tsSize) ||
  326.             (CharWidth (' ') * tabChars != fTabWidth)) {
  327.         disp = fDisplay;
  328.         fStyle = *theStyle;
  329.         GetFontInfo (&info);
  330.         newheight = info.ascent + info.descent + info.leading;
  331.         newbottom = fBounds.top + ((fBounds.bottom - fBounds.top) /
  332.             fLineHeight) * newheight;
  333.         fTabWidth = CharWidth (' ') * tabChars;
  334.         fCurVers += 1;
  335.         if (fCurVers == 0) fCurVers = 1;
  336.         if ((disp.top > fBounds.top) && (disp.bottom >= fBounds.bottom)) {
  337.             fLineHeight = newheight;
  338.             fBounds.bottom = newbottom;
  339.             Recalc (newbottom + disp.top - disp.bottom, newbottom, FALSE);
  340.             delta = disp.bottom - fBounds.bottom;
  341.         } else {
  342.             Vert2Buf (disp.top, &th, &pos);
  343.             oldv = Buf2Vert (th, pos);
  344.             delta = oldv - ((oldv - fBounds.top) / fLineHeight) * newheight -
  345.                 fBounds.top;
  346.             fLineHeight = newheight;
  347.             fBounds.top += delta;
  348.             fBounds.bottom = newbottom + delta;
  349.             Recalc (oldv, disp.bottom, FALSE);
  350.             delta = oldv - Buf2Vert (th, pos);
  351.             if (disp.bottom > fBounds.bottom + delta)
  352.                 delta = disp.bottom - fBounds.bottom;
  353.         }
  354.         if (fBounds.top + delta > disp.top) delta = disp.top - fBounds.top;
  355.         fBounds.top += delta;
  356.         fBounds.bottom += delta;
  357.         SetPort (savedPort);
  358.         if (redraw) {
  359.             PenNormal ();
  360.             EraseRect (&disp);
  361.             Draw (&disp);
  362.         }
  363.     } else
  364.         SetPort (savedPort);
  365. }
  366.  
  367. //------------------------------------------------------------------------------
  368.  
  369. #pragma segment SMUDDocRes
  370.  
  371. pascal TBHandle TBigText::AppendBuf (TBHandle th, long size)
  372. {
  373.     TBHandle h;
  374.     LSHandle lh;
  375.     
  376.     h = (TBHandle) NewPermHandle (sizeof (TextBuffer) - kTBSize + size);
  377.     lh = (LSHandle) NewPermHandle (sizeof (short) * 2);
  378.     if (h && lh) {
  379.         (**h).bNext = NULL;
  380.         (**h).bLength = 0;
  381.         (**h).bLines = 1;
  382.         (**h).bVersion = 0;
  383.         (**h).bStarts = lh;
  384.         (**lh) [0] = 0;
  385.         (**lh) [1] = 0;
  386.         if (th)
  387.             (**th).bNext = h;
  388.         else
  389.             fText = h;
  390.         fBounds.bottom += fLineHeight;
  391.     } else {
  392.         if (h) DisposeIfHandle (h);
  393.         if (lh) DisposeIfHandle (lh);
  394.     }
  395.     return h;
  396. }
  397.  
  398. //------------------------------------------------------------------------------
  399.  
  400. #pragma segment SMUDDocRes
  401.  
  402. pascal long TBigText::AppendChars (unsigned char *buf, long count)
  403. {
  404.     long pos, len, lsize, act;
  405.     Boolean newBuf, oldMemLow;
  406.     unsigned char *b, ch;
  407.     TBHandle th, oth;
  408.     
  409.     oldMemLow = gMemIsLow;
  410.     th = fText;
  411.     while ((**th).bNext) th = (**th).bNext;
  412.     pos = (**th).bLength;
  413.     oth = th;
  414.     ch = (pos > 0) ? (**th).bBuf [pos - 1] : 0;
  415.     newBuf = (pos >= kTBSize) && (ch == chReturn);
  416.     if (newBuf) pos = 0;
  417.     act = 0;
  418.     while (act < count) {
  419.         if (!newBuf) ClrLines (th);
  420.         len = 0;
  421.         b = buf;
  422.         while ((len < count - act) && ((ch != chReturn) ||
  423.                 (pos + len < kTBSize)) && (pos + len < kMaxTBSize)) {
  424.             ch = *b++;
  425.             len += 1;
  426.         }
  427.         if (newBuf) {
  428.             th = AppendBuf (th, len);
  429.             if (!th) Debugger ();
  430.         } else {
  431.             lsize = sizeof (TextBuffer) - kTBSize + pos + len;
  432.             SetPermHandleSize ((Handle) th, lsize);
  433.             if (GetHandleSize ((Handle) th) != lsize) Debugger ();
  434.         }
  435.         BlockMove (buf, (**th).bBuf + pos, len);
  436.         buf += len;
  437.         (**th).bLength = (short) (pos + len);
  438.         (**(**th).bStarts) [(**th).bLines] = (short) (pos + len);
  439.         act += len;
  440.         fLength += len;
  441.         newBuf = TRUE;
  442.         pos = 0;
  443.         if ((gMemIsLow && !oldMemLow) || (!gMemReserve && !gMemReserve2)) break;
  444.     }
  445.     while (oth) {
  446.         RecalcBuf (oth);
  447.         oth = (**oth).bNext;
  448.     }
  449.     return act;
  450. }
  451.  
  452. //------------------------------------------------------------------------------
  453.  
  454. #pragma segment SMUDDocRes
  455.  
  456. pascal long TBigText::Buf2Char (TBHandle th, long pos)
  457. {
  458.     long p;
  459.     TBHandle h;
  460.     
  461.     h = fText;
  462.     p = 0;
  463.     while (h && (h != th)) {
  464.         p += (**h).bLength;
  465.         h = (**h).bNext;
  466.     }
  467.     if (h) p += pos;
  468.     return p;
  469. }
  470.  
  471. //------------------------------------------------------------------------------
  472.  
  473. #pragma segment SMUDDocRes
  474.  
  475. pascal long TBigText::Buf2Hor (TBHandle th, long pos)
  476. {
  477.     TextStyle theStyle;
  478.     long len, p, hor, width;
  479.     SignedByte oldState;
  480.     
  481.     theStyle = fStyle;
  482.     SetPortTextStyle (&theStyle);
  483.     p = (**(**th).bStarts) [FindLine (th, pos)];
  484.     hor = 0;
  485.     while (p < pos) {
  486.         len = ChunkSize (th, p, pos);
  487.         if (len > 0) {
  488.             oldState = HGetState ((Handle) th);
  489.             HLock ((Handle) th);
  490.             hor += TextWidth ((**th).bBuf, (short) p, (short) (len));
  491.             HSetState ((Handle) th, oldState);
  492.             p += len;
  493.         } else {
  494.             if ((**th).bBuf [p] == chTab)
  495.                 hor += fTabWidth - (hor % fTabWidth);
  496.             else
  497.                 hor = fBounds.right;
  498.             p += 1;
  499.         }
  500.     }
  501.     if (fAutoWrap) {
  502.         width = fBounds.right - fBounds.left;
  503.         if (width < 0) width = 0;
  504.         if (hor > width) hor = width;
  505.     }
  506.     return fBounds.left + hor;
  507. }
  508.  
  509. //------------------------------------------------------------------------------
  510.  
  511. #pragma segment SMUDDocRes
  512.  
  513. pascal long TBigText::Buf2Vert (TBHandle th, long pos)
  514. {
  515.     TBHandle h;
  516.     long lines;
  517.     
  518.     h = fText;
  519.     lines = 0;
  520.     while (h != th) {
  521.         lines += (**h).bLines;
  522.         h = (**h).bNext;
  523.     }
  524.     return fBounds.top + ((lines + FindLine (th, pos)) * fLineHeight);
  525. }
  526.  
  527. //------------------------------------------------------------------------------
  528.  
  529. #pragma segment SMUDDocRes
  530.  
  531. pascal void TBigText::BuildReserve (Boolean build)
  532. {
  533.     long size;
  534.     
  535.     if (fMemReserve) {
  536.         DisposIfHandle (fMemReserve);
  537.         fMemReserve = NULL;
  538.     }
  539.     if (build) {
  540.         size = fLength + (sizeof (short) * (fBounds.bottom - fBounds.top)) /
  541.             fLineHeight;
  542.         if (size < kBTRsrv) fMemReserve = NewPermHandle (kBTRsrv - size);
  543.     }
  544. }
  545.  
  546. //------------------------------------------------------------------------------
  547.  
  548. #pragma segment SMUDDocRes
  549.  
  550. pascal void TBigText::Char2Buf (long charPos, TBHandle *th, long *pos)
  551. {
  552.     TBHandle h;
  553.     
  554.     h = fText;
  555.     while (h && (**h).bNext && (charPos >= (**h).bLength)) {
  556.         charPos -= (**h).bLength;
  557.         h = (**h).bNext;
  558.     }
  559.     *th = h;
  560.     *pos = (charPos < (**h).bLength) ? charPos : (**h).bLength;
  561. }
  562.  
  563. //------------------------------------------------------------------------------
  564.  
  565. #pragma segment SMUDDocRes
  566.  
  567. pascal long TBigText::ChunkSize (TBHandle th, long pos, long epos)
  568. {
  569.     long l, max;
  570.     unsigned char *cp, ch;
  571.     
  572.     cp = (**th).bBuf + pos;
  573.     max = epos - pos;
  574.     for (l = 0; l < max; l++) {
  575.         ch = *cp++;
  576.         if ((ch == chTab) || (ch == chReturn)) break;
  577.     }
  578.     return l;
  579. }
  580.  
  581. //------------------------------------------------------------------------------
  582.  
  583. #pragma segment SMUDDocRes
  584.  
  585. pascal void TBigText::ClrLines (TBHandle th)
  586. {
  587.     LSHandle lh;
  588.  
  589.     fBounds.bottom -= ((**th).bLines - 1) * fLineHeight;
  590.     (**th).bLines = 1;
  591.     lh = (**th).bStarts;
  592.     SetPermHandleSize ((Handle) lh, sizeof (short) * 2);
  593.     (**lh) [1] = (**th).bLength;
  594.     (**th).bVersion = 0;
  595. }
  596.  
  597. //------------------------------------------------------------------------------
  598.  
  599. #pragma segment SMUDDocRes
  600.  
  601. pascal void TBigText::Draw (Rect *area)
  602. {
  603.     TextStyle theStyle;
  604.     FontInfo info;
  605.     TBHandle th;
  606.     long pos, base, len, hor, epos, height, top;
  607.     VRect vr;
  608.     Rect dr;
  609.     SignedByte oldState;
  610.     Point pt;
  611.  
  612.     dr = fDisplay;
  613.     if (SectRect (&dr, area, &dr)) {
  614.         PenNormal ();
  615.         theStyle = fStyle;
  616.         SetPortTextStyle (&theStyle);
  617.         RectToVRect (area, &vr);
  618.         Vert2Buf (vr.top, &th, &pos);
  619.         top = Buf2Vert (th, pos);
  620.         height = vr.bottom - top;
  621.         GetFontInfo (&info);
  622.         base = area->top - vr.top + top + info.ascent;
  623.         GetClip (Draw_clip);
  624.         RectRgn (Draw_tmp, &dr);
  625.         SectRgn (qd.thePort->clipRgn, Draw_tmp, Draw_tmp);
  626.         SetClip (Draw_tmp);
  627.         EraseRect (area);
  628.         while (th && (height > 0)) {
  629.             epos = (**(**th).bStarts) [FindLine (th, pos) + 1];
  630.             hor = 0;
  631.             while (pos < epos) {
  632.                 len = ChunkSize (th, pos, epos);
  633.                 if (len > 0) {
  634.                     MoveTo ((short) (fBounds.left + hor), (short) base);
  635.                     oldState = HGetState ((Handle) th);
  636.                     HLock ((Handle) th);
  637.                     DrawText ((**th).bBuf, (short) pos, (short) len);
  638.                     HSetState ((Handle) th, oldState);
  639.                     GetPen (&pt);
  640.                     hor = pt.h - fBounds.left;
  641.                     pos += len;
  642.                 } else {
  643.                     if ((**th).bBuf [pos] == chTab)
  644.                         hor += fTabWidth - (hor % fTabWidth);
  645.                     pos += 1;
  646.                 }
  647.             }
  648.             if (epos == (**th).bLength) {
  649.                 th = (**th).bNext;
  650.                 pos = 0;
  651.             }
  652.             base += fLineHeight;
  653.             height -= fLineHeight;
  654.         }
  655.         if (fActive) Highlight (fSelStart, fSelEnd);
  656.         SetClip (Draw_clip);
  657.     }
  658. }
  659.  
  660. //------------------------------------------------------------------------------
  661.  
  662. #pragma segment SMUDDocRes
  663.  
  664. pascal void TBigText::DropBuf (void)
  665. {
  666.     TBHandle th;
  667.     
  668.     th = fText;
  669.     fBounds.top += (**th).bLines * fLineHeight;
  670.     fLength -= (**th).bLength;
  671.     fText = (**th).bNext;
  672.     DisposeIfHandle ((**th).bStarts);
  673.     DisposeIfHandle (th);
  674. }
  675.  
  676. //------------------------------------------------------------------------------
  677.  
  678. #pragma segment SMUDDocRes
  679.  
  680. pascal Boolean TBigText::DropSome (void)
  681. {
  682.     long actsize;
  683.     
  684.     fMaxLowSize = kBTRsrv + ((fMaxLowSize - kBTRsrv) * 9) / 10;
  685.     actsize = fLength + (sizeof (short) * (fBounds.bottom - fBounds.top)) /
  686.         fLineHeight;
  687.     if (actsize > fMaxLowSize) {
  688.         fSuperView->Focus ();
  689.         BTDrop (actsize - fMaxLowSize, kRedraw);
  690.         ((TLogView *) fSuperView)->SynchScrollBar (kRedraw);
  691.         return TRUE;
  692.     } else
  693.         return FALSE;
  694. }
  695.  
  696. //------------------------------------------------------------------------------
  697.  
  698. #pragma segment SMUDDocRes
  699.  
  700. pascal long TBigText::FindLine (TBHandle th, long pos)
  701. {
  702.     long l, m, r;
  703.     LSHandle lh;
  704.     
  705.     lh = (**th).bStarts;
  706.     l = 0;
  707.     r = (**th).bLines - 1;
  708.     while (l < r) {
  709.         m = (l + r + 1) / 2;
  710.         if (pos >= (**lh) [m])
  711.             l = m;
  712.         else if (m == l + 1)
  713.             break;
  714.         else
  715.             r = m;
  716.     }
  717.     return l;
  718. }
  719.  
  720. //------------------------------------------------------------------------------
  721.  
  722. #pragma segment SMUDDocRes
  723.  
  724. pascal void TBigText::FindRun (short clicks, long h, long v, long *cbeg,
  725.         long *cend, long *cloc)
  726. {
  727.     TBHandle th;
  728.     LSHandle lh;
  729.     long pos, bpos, epos, bline, eline;
  730.     Boolean left;
  731.     
  732.     if (fLength == 0) {
  733.         *cbeg = 0;
  734.         *cend = 0;
  735.         *cloc = 0;
  736.     } else {
  737.         if (v < fDisplay.top) {
  738.             v = fDisplay.top;
  739.             h = fBounds.left - 1;
  740.         } else if (v > fDisplay.bottom) {
  741.             v = fDisplay.bottom;
  742.             h = fBounds.left - 1;
  743.         }
  744.         Vert2Buf (v, &th, &bpos);
  745.         if (bpos >= (**th).bLength) {
  746.             epos = bpos;
  747.             if (bpos > 0) bpos -= 1;
  748.             left = FALSE;
  749.         } else {
  750.             Hor2Buf (h, th, &bpos, &left);
  751.             epos = (bpos >= (**th).bLength) ? bpos : bpos + 1;
  752.         }
  753.         pos = left ? bpos : epos;
  754.         if (clicks == 1) {
  755.             bpos = pos;
  756.             epos = pos;
  757.         } else if (clicks == 2) {
  758.             if (pWChars [(**th).bBuf [bpos]]) {
  759.                 while ((bpos > 0) && pWChars [(**th).bBuf [bpos - 1]])
  760.                     bpos -= 1;
  761.                 while ((epos < (**th).bLength) && pWChars [(**th).bBuf [epos]])
  762.                     epos += 1;
  763.             }
  764.         } else /* clicks > 2 */ {
  765.             lh = (**th).bStarts;
  766.             bline = FindLine (th, bpos);
  767.             eline = bline + 1;
  768.             while ((bline > 0) &&
  769.                     ((**th).bBuf [(**lh) [bline] - 1] != chReturn))
  770.                 bline -= 1;
  771.             while ((eline < (**th).bLines) &&
  772.                     ((**th).bBuf [(**lh) [eline] - 1] != chReturn))
  773.                 eline += 1;
  774.             bpos = (**lh) [bline];
  775.             epos = (**lh) [eline];
  776.         }
  777.         *cbeg = Buf2Char (th, bpos);
  778.         *cend = epos - bpos + *cbeg;
  779.         *cloc = pos - bpos + *cbeg;
  780.     }
  781. }
  782.  
  783. //------------------------------------------------------------------------------
  784.  
  785. #pragma segment MAClose
  786.  
  787. pascal void TBigText::Free (void)
  788. {
  789.     while (fText) DropBuf ();
  790.     if (fMemReserve) DisposIfHandle (fMemReserve);
  791.     fMemReserve = NULL;
  792.     inherited::Free ();
  793. }
  794.  
  795. //------------------------------------------------------------------------------
  796.  
  797. pascal void TBigText::Highlight (long start, long end)
  798. {
  799.     TBHandle th;
  800.     long pos, tmp;
  801.     VRect vr;
  802.     Rect r, tr;
  803.     short left, right;
  804.  
  805.     if (start == end) return;
  806.     if (start > end) {
  807.         tmp = end; end = start; start = tmp;
  808.     }
  809.     Char2Buf (start, &th, &pos);
  810.     vr.top = Buf2Vert (th, pos);
  811.     vr.left = Buf2Hor (th, pos);
  812.     Char2Buf (end, &th, &pos);
  813.     vr.bottom = Buf2Vert (th, pos) + fLineHeight;
  814.     vr.right = Buf2Hor (th, pos);
  815.     VRectToRect (&vr, &r);
  816.     if ((r.top > fDisplay.bottom) || (r.bottom < fDisplay.top)) return;
  817.     left = (fBounds.left < -32000) ? -32000 : (short) fBounds.left;
  818.     right = (fBounds.right > 32000) ? 32000 : (short) fBounds.right;
  819.     PenPat (qd.gray);
  820.     PenMode (patXor);
  821.     UseSelectionColor ();
  822.     if (r.top + fLineHeight != r.bottom) {
  823.         tr = r;
  824.         tr.bottom = r.top + (short) fLineHeight;
  825.         tr.right = right;
  826.         if (tr.right > tr.left) InvertRect (&tr);
  827.         tr.top = r.top + (short) fLineHeight;
  828.         tr.bottom = r.bottom - (short) fLineHeight;
  829.         tr.left = left;
  830.         tr.right = right;
  831.         if (tr.top < tr.bottom) InvertRect (&tr);
  832.         tr = r;
  833.         tr.top = r.bottom - (short) fLineHeight;
  834.         tr.left = left;
  835.         if (tr.right > tr.left) InvertRect (&tr);
  836.     } else
  837.         InvertRect (&r);
  838. }
  839.  
  840. //------------------------------------------------------------------------------
  841.  
  842. #pragma segment SMUDDocRes
  843.  
  844. pascal void TBigText::Hor2Buf (long h, TBHandle th, long *pos, Boolean *left)
  845. {
  846.     TextStyle theStyle;
  847.     long p, len, hor, i, w, epos;
  848.     SignedByte oldState;
  849.     
  850.     theStyle = fStyle;
  851.     SetPortTextStyle (&theStyle);
  852.     p = *pos;
  853.     h -= fBounds.left;
  854.     hor = 0;
  855.     w = 0;
  856.     epos = (**(**th).bStarts) [FindLine (th, p) + 1];
  857.     while (p < epos) {
  858.         len = ChunkSize (th, p, epos);
  859.         if (len > 0) {
  860.             if (len > kMaxChunk) len = kMaxChunk;
  861.             oldState = HGetState ((Handle) th);
  862.             HLock ((Handle) th);
  863.             MeasureText ((short) len, (Ptr) ((**th).bBuf + p),
  864.                 (Ptr) pCharLocs);
  865.             HSetState ((Handle) th, oldState);
  866.             for (i = 1; i <= len; i++) {
  867.                 w = pCharLocs [i] - pCharLocs [i - 1];
  868.                 if (hor + w > h) break;
  869.                 hor += w;
  870.                 p += 1;
  871.             }
  872.             if (i <= len) break;
  873.         } else if ((**th).bBuf [p] == chTab) {
  874.             w = fTabWidth - (hor % fTabWidth);
  875.             if (hor + w > h) break;
  876.             hor += w;
  877.             p += 1;
  878.         } else /* chReturn */ {
  879.             w = (fBounds.right - fBounds.left) * 2;
  880.             break;
  881.         }
  882.     }
  883.     *left = (p < epos) && (h < hor + (w / 2));
  884.     if (p < epos)
  885.         *pos = p;
  886.     else if (epos > *pos)
  887.         *pos = epos - 1;
  888. }
  889.  
  890. //------------------------------------------------------------------------------
  891.  
  892. #pragma segment AOpen
  893.  
  894. pascal void TBigText::IBigText (Rect *display, TextStyle *theStyle,
  895.         long tabChars, TView *itsView)
  896. {
  897.     if (!BTScroll_clip) {
  898.         BTScroll_clip = NewRgn ();
  899.         FailNIL (BTScroll_clip);
  900.     }
  901.     if (!BTScroll_scrl) {
  902.         BTScroll_scrl = NewRgn ();
  903.         FailNIL (BTScroll_scrl);
  904.     }
  905.     if (!Draw_clip) {
  906.         Draw_clip = NewRgn ();
  907.         FailNIL (Draw_clip);
  908.     }
  909.     if (!Draw_tmp) {
  910.         Draw_tmp = NewRgn ();
  911.         FailNIL (Draw_tmp);
  912.     }
  913.     fText = NULL;
  914.     fMemReserve = NULL;
  915.     IObject ();
  916.     fSuperView = itsView;
  917.     IObject ();
  918.     fSelStart = 0;
  919.     fSelEnd = 0;
  920.     fLength = 0;
  921.     fMaxLength = 0;
  922.     fMaxLowSize = kBTRsrv;
  923.     fCurVers = 1;
  924.     fDisplay = *display;
  925.     fBounds.top = fDisplay.top;
  926.     fBounds.left = fDisplay.left;
  927.     fBounds.bottom = fDisplay.top;
  928.     fBounds.right = fDisplay.right;
  929.     fActive = FALSE;
  930.     fAutoWrap = TRUE;
  931.     fLineHeight = 11; /* dummy, needed for AppendBuf, changed in BTSetStyle */
  932.     FailNIL (AppendBuf (NULL, 0));
  933.     BuildReserve (TRUE);
  934.     FailNIL (fMemReserve);
  935.     BTSetStyle (theStyle, tabChars, kDontRedraw);
  936. }
  937.  
  938. //------------------------------------------------------------------------------
  939.  
  940. #pragma segment SMUDDocRes
  941.  
  942. pascal void TBigText::Recalc (long vfrom, long vto, Boolean adjTop)
  943. {
  944.     TBHandle th, eh;
  945.     long oldBot, delta, pos;
  946.     
  947.     BuildReserve (FALSE);
  948.     do { /* recalc more than was asked (simplifies scrolling) */
  949.         delta = 0;
  950.         if (vto > fBounds.bottom) delta = fBounds.bottom - vto;
  951.         if (vfrom + delta < fBounds.top) delta = fBounds.top - vfrom;
  952.         vfrom += delta;
  953.         vto += delta;
  954.         Vert2Buf (vfrom, &th, &pos);
  955.         Vert2Buf (vto, &eh, &pos);
  956.         eh = (**eh).bNext;
  957.         oldBot = fBounds.bottom;
  958.         while (th && (th != eh)) {
  959.             RecalcBuf (th);
  960.             th = (**th).bNext;
  961.         }
  962.         delta = fBounds.bottom - oldBot;
  963.         if (adjTop) {
  964.             fBounds.top -= delta;
  965.             fBounds.bottom -= delta;
  966.         }
  967.     } while (delta < 0); /* recalc again if number of lines decreased */
  968.     BuildReserve (TRUE);
  969. }
  970.  
  971. //------------------------------------------------------------------------------
  972.  
  973. #pragma segment SMUDDocRes
  974.  
  975. pascal void TBigText::RecalcBuf (TBHandle th)
  976. {
  977.     TextStyle theStyle;
  978.     long pos, epos, line, len, maxlen, hor, width;
  979.     long l, brk, oldbrk, oldloc;
  980.     LSHandle lh;
  981.     SignedByte oldState;
  982.     unsigned char ch;
  983.     Boolean done;
  984.     
  985.     if ((**th).bVersion == fCurVers) return;
  986.     done = TRUE;
  987.     lh = (**th).bStarts;
  988.     (**lh) [0] = 0;
  989.     line = 1;
  990.     pos = 0;
  991.     if (fAutoWrap) {
  992.         theStyle = fStyle;
  993.         SetPortTextStyle (&theStyle);
  994.         epos = (**th).bLength;
  995.         width = fBounds.right - fBounds.left;
  996.         if (width <= 0) width = 1;
  997.         hor = 0;
  998.         while (pos < epos) {
  999.             maxlen = ChunkSize (th, pos, epos);
  1000.             len = (maxlen > kMaxChunk) ? kMaxChunk : maxlen;
  1001.             if (len > 0) {
  1002.                 oldState = HGetState ((Handle) th);
  1003.                 HLock ((Handle) th);
  1004.                 MeasureText ((short) len, (Ptr) ((**th).bBuf + pos),
  1005.                     (Ptr) pCharLocs);
  1006.                 HSetState ((Handle) th, oldState);
  1007.                 oldloc = 0;
  1008.             }
  1009.             oldbrk = 0;
  1010.             while (oldbrk < len) {
  1011.                 l = oldbrk + 2;
  1012.                 while ((l <= len) && (hor + pCharLocs [l] - oldloc <= width))
  1013.                     l += 1;
  1014.                 if ((l <= len) && ((**th).bBuf [pos + l - 1] == chSpace))
  1015.                     l += 1;
  1016.                 brk = l - 1;
  1017.                 if (l > len) {
  1018.                     if ((len < maxlen) && (oldbrk > 0)) {
  1019.                         pos += oldbrk;
  1020.                         break;
  1021.                     }
  1022.                     hor += pCharLocs [brk] - oldloc;
  1023.                     oldloc = pCharLocs [brk];
  1024.                     pos += brk;
  1025.                 } else {
  1026.                     while ((brk > oldbrk) &&
  1027.                             ((**th).bBuf [pos + brk - 1] != chSpace))
  1028.                         brk -= 1;
  1029.                     if ((brk <= oldbrk) && (hor == 0)) brk = l - 1;
  1030.                     if ((brk <= oldbrk) && (hor == 0)) brk = oldbrk + 1;
  1031.                     done &= SetLSVal (lh, line++, (short) (pos + brk));
  1032.                     hor = 0;
  1033.                     oldloc = pCharLocs [brk];
  1034.                 }
  1035.                 oldbrk = brk;
  1036.             }
  1037.             while ((pos < epos) && ((len == maxlen) || (oldbrk == 0))) {
  1038.                 ch = (**th).bBuf [pos];
  1039.                 if (ch == chTab) {
  1040.                     if (hor >= width) {
  1041.                         done &= SetLSVal (lh, line++, (short) pos);
  1042.                         hor = 0;
  1043.                     }
  1044.                     hor += fTabWidth - (hor % fTabWidth);
  1045.                     pos += 1;
  1046.                 } else if (ch == chReturn) {
  1047.                     pos += 1;
  1048.                     done &= SetLSVal (lh, line++, (short) pos);
  1049.                     hor = 0;
  1050.                 } else
  1051.                     break;
  1052.             }
  1053.         }
  1054.         if ((epos > 0) && ((**th).bBuf [epos - 1] == chReturn))
  1055.             line -= 1;
  1056.         else
  1057.             done &= SetLSVal (lh, line, (short) epos);
  1058.     } else {
  1059.         epos = (**th).bLength - 1;
  1060.         while (pos < epos)
  1061.             if ((**th).bBuf [pos++] == chReturn)
  1062.                 done &= SetLSVal (lh, line++, (short) pos);
  1063.         done &= SetLSVal (lh, line, (short) epos + 1);
  1064.     }
  1065.     if (done)
  1066.         (**th).bVersion = fCurVers;
  1067.     else {
  1068.         line = 1;
  1069.         SetLSVal (lh, line, (**th).bLength);
  1070.         (**th).bVersion = 0;
  1071.     }
  1072.     SetPermHandleSize ((Handle) lh, sizeof (short) * (long) (line + 1));
  1073.     fBounds.bottom += (line - (**th).bLines) * fLineHeight;
  1074.     (**th).bLines = (short) line;
  1075. }
  1076.  
  1077. //------------------------------------------------------------------------------
  1078.  
  1079. #pragma segment SMUDDocRes
  1080.  
  1081. pascal Boolean TBigText::SetLSVal (LSHandle lh, long line, short val)
  1082. {
  1083.     long size;
  1084.     Boolean done;
  1085.     
  1086.     size = GetHandleSize ((Handle) lh) / sizeof (short);
  1087.     if (size <= line) {
  1088.         size += line + kLSChunk;
  1089.         size *= sizeof (short);
  1090.         SetPermHandleSize ((Handle) lh, size);
  1091.         done = GetHandleSize ((Handle) lh) == size;
  1092.     } else
  1093.         done = TRUE;
  1094.     if (done) (**lh) [line] = val;
  1095.     return done;
  1096. }
  1097.  
  1098. //------------------------------------------------------------------------------
  1099.  
  1100. #pragma segment SMUDDocRes
  1101.  
  1102. pascal void TBigText::Vert2Buf (long v, TBHandle *th, long *pos)
  1103. {
  1104.     TBHandle h;
  1105.     
  1106.     v = (v - fBounds.top) / fLineHeight;
  1107.     if (v < 0) v = 0;
  1108.     h = fText;
  1109.     while ((**h).bNext && (v >= (**h).bLines)) {
  1110.         v -= (**h).bLines;
  1111.         h = (**h).bNext;
  1112.     }
  1113.     *th = h;
  1114.     if (v >= (**h).bLines)
  1115.         *pos = (**h).bLength;
  1116.     else
  1117.         *pos = (**(**h).bStarts) [v];
  1118. }
  1119.  
  1120. //------------------------------------------------------------------------------
  1121.